package com.samphanie.security.rest;

import com.nimbusds.jose.jwk.JWKSet;
import com.nimbusds.jose.jwk.RSAKey;
import com.samphanie.common.constants.SystemConstants;
import com.samphanie.common.enums.ResultCode;
import com.samphanie.common.execetion.ApiException;
import com.samphanie.common.service.IRedisService;
import com.samphanie.common.utils.ApiResponse;
import com.samphanie.common.utils.SpringEnvironmentUtils;
import com.samphanie.security.config.SocialConfig;
import com.samphanie.security.domain.dto.Oauth2TokenDto;
import com.xkcoding.justauth.AuthRequestFactory;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import lombok.RequiredArgsConstructor;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.oauth2.common.OAuth2AccessToken;
import org.springframework.security.oauth2.provider.endpoint.TokenEndpoint;
import org.springframework.web.HttpRequestMethodNotSupportedException;
import org.springframework.web.bind.annotation.*;
import springfox.documentation.annotations.ApiIgnore;

import java.security.KeyPair;
import java.security.Principal;
import java.security.interfaces.RSAPublicKey;
import java.util.Map;

/**
 * @author ZSY
 * @email 1451691457@qq.com
 */
@Slf4j
@RequiredArgsConstructor
@RestController
@RequestMapping("/oauth")
public class AuthController {

    private final TokenEndpoint tokenEndpoint;
    private final KeyPair keyPair;
    private final IRedisService redisService;
    private final AuthRequestFactory factory;
    private final SocialConfig socialConfig;
    private final SpringEnvironmentUtils springEnvironmentUtils;

    @ApiImplicitParams({
            @ApiImplicitParam(name = "grant_type", value = "授权模式", paramType = "query", dataTypeClass = String.class, required = true),
            @ApiImplicitParam(name = "client_id", value = "Oauth2客户端ID", paramType = "query", dataTypeClass = String.class),
            @ApiImplicitParam(name = "client_secret", value = "Oauth2客户端秘钥", paramType = "query", dataTypeClass = String.class),
            @ApiImplicitParam(name = "refresh_token", value = "刷新token", paramType = "query", dataTypeClass = String.class),
            @ApiImplicitParam(name = "username", value = "用户名", paramType = "query", dataTypeClass = String.class),
            @ApiImplicitParam(name = "password", value = "密码", paramType = "query", dataTypeClass = String.class),
            @ApiImplicitParam(name = "scope", value = "授权范围", paramType = "query", dataTypeClass = String.class)
    })
    @RequestMapping(value = "/token", method = {RequestMethod.POST, RequestMethod.GET})
    public ApiResponse<?> getAccessToken(@ApiIgnore Principal principal, @ApiIgnore @RequestParam Map<String, String> parameters) {

        try {
            OAuth2AccessToken oAuth2AccessToken = tokenEndpoint.postAccessToken(principal, parameters).getBody();

            Oauth2TokenDto oauth2TokenDto = Oauth2TokenDto.builder()
                    .token(oAuth2AccessToken.getValue())
                    .refreshToken(oAuth2AccessToken.getRefreshToken().getValue())
                    .expiresIn(oAuth2AccessToken.getExpiresIn())
                    .tokenHead(SystemConstants.JWT_TOKEN_PREFIX)
                    .build();

            return ApiResponse.success(oauth2TokenDto);
        } catch (Exception e) {
           throw new ApiException(e.getMessage());
        }
    }

    /**
     * 为了和 Spring Security 5.1 以上版本的 Resource Server 兼容, 让 Spring Security OAuth2 支持 JWK 暴露 JWK 的接入点
     * @return JWKSet
     */
    @GetMapping("/rsa/publicKey")
    public Map<String, Object> getPublicKey() {
        RSAPublicKey publicKey = (RSAPublicKey) this.keyPair.getPublic();
        RSAKey key = new RSAKey.Builder(publicKey).build();
        return new JWKSet(key).toJSONObject();
    }

//    @ApiImplicitParams({
//            @ApiImplicitParam(name = "grant_type", value = "授权模式", paramType = "query", dataTypeClass = String.class, required = true),
//            @ApiImplicitParam(name = "client_id", value = "Oauth2客户端ID", paramType = "query", dataTypeClass = String.class),
//            @ApiImplicitParam(name = "client_secret", value = "Oauth2客户端秘钥", paramType = "query", dataTypeClass = String.class),
//            @ApiImplicitParam(name = "refresh_token", value = "刷新token", paramType = "query", dataTypeClass = String.class),
//            @ApiImplicitParam(name = "username", value = "用户名", paramType = "query", dataTypeClass = String.class),
//            @ApiImplicitParam(name = "password", value = "密码", paramType = "query", dataTypeClass = String.class),
//            @ApiImplicitParam(name = "scope", value = "使用范围", paramType = "query", dataTypeClass = String.class)
//    })
//    @PostMapping("/token")
//    public ApiResponse<?> postAccessToken(@ApiIgnore Principal principal, @ApiIgnore @RequestParam Map<String, String> parameters) {
//
//        try {
//            OAuth2AccessToken oAuth2AccessToken = tokenEndpoint.postAccessToken(principal, parameters).getBody();
//
//            Oauth2TokenDto oauth2TokenDto = Oauth2TokenDto.builder()
//                    .token(oAuth2AccessToken.getValue())
//                    .refreshToken(oAuth2AccessToken.getRefreshToken().getValue())
//                    .expiresIn(oAuth2AccessToken.getExpiresIn())
//                    .tokenHead(SystemConstants.JWT_TOKEN_PREFIX)
//                    .build();
//
//            return ApiResponse.success(oauth2TokenDto);
//        } catch (Exception e) {
//            log.debug("异常信息：{}",e.getMessage());
//            return ApiResponse.failed(e.getMessage());
//        }
//    }

//    @DeleteMapping("/logout")
//    public ApiResponse<?> logout(HttpServletRequest request) {
//        String token = request.getHeader(SystemConstants.JWT_TOKEN_HEADER);
//        String realToken = token.replace(SystemConstants.JWT_TOKEN_PREFIX, "");
//        JWSObject jwsObject = null;
//        try {
//            jwsObject = JWSObject.parse(realToken);
//            String payload = jwsObject.getPayload().toString();
//            JSONObject jsonObject = JSONUtil.parseObj(payload);
//            // JWT唯一标识
//            String jti = jsonObject.getStr("jti");
//            // JWT过期时间戳(单位:秒)
//            long exp = jsonObject.getLong("exp");
//            long currentTimeSeconds = System.currentTimeMillis() / 1000;
//            // token已过期
//            if (exp < currentTimeSeconds) {
//                return ApiResponse.failed(ResultCode.USER_ERROR_A0230);
//            }
//            redisService.set(AuthConstants.TOKEN_BLACKLIST_PREFIX + jti, null, (exp - currentTimeSeconds));
//            return ApiResponse.success();
//        } catch (ParseException e) {
//            throw new ApiException(ResultCode.ERROR);
//        }
//    }
//
//    @ApiOperation(value = "第三方登录", notes = "第三方登录")
//    @GetMapping("/login/{oauthType}")
//    public void login(@PathVariable String oauthType, HttpServletResponse response) throws IOException {
//        AuthRequest authRequest = factory.get(oauthType);
//        response.sendRedirect(authRequest.authorize(oauthType + "::" + AuthStateUtils.createState()));
//    }
//
//    @ApiOperation(value = "第三方登录回调", notes = "第三方登录回调")
//    @GetMapping("/callback/{oauthType}")
//    public String callback(@PathVariable String oauthType, AuthCallback callback) {
//
//        //        AuthRequest authRequest = factory.get(oauthType);
//        //        AuthResponse response = authRequest.login(callback);
//        //        log.info("【response】= {}", JSONUtil.toJsonStr(response));
//
//        // String url = socialConfig.getUrl() + "?code=" + oauthType + "-" + callback.getCode() + "&state=" + callback.getState();
//        String url = springEnvironmentUtils.getLocalHostAddress() + "/oauth/token" + "?code=" + oauthType + "-" + callback.getCode() + "&state=" + callback.getState() + "&client_id=admin-client&client_secret=secret&grant_type=social";
//        log.debug("url:{}", url);
//        //跳转到指定页面
//        return "redirect:" + url;
//    }

}
